/**
 *     Copyright (c) 2006-03-12 Yazy<yazy@mail.csdn.net>
 *
 */

#ifndef __yisc_cgi_request_hxx____YAZY__
#define __yisc_cgi_request_hxx____YAZY__ 1
#       include <iostream>
#       include <sstream>
#       include <string>
#       include <map>

namespace yisc { namespace cgi {

  // an example of QUERY_STRING unencoding:
  // see: http://www.cs.tut.fi/~jkorpela/forms/cgic.html
  template<typename TChar>
  void decodeQueryString(const TChar * sBegin, const TChar * sEnd,
                         std::basic_string<TChar>& dest)
  {
    typedef std::basic_string<TChar>    TString;
    for (const TChar * i = sBegin; i != sEnd; ++i)
      {
        if ((*i) == TChar('+')) dest.push_back(TChar(' '));
        else if ((*i) == TChar('%'))
          {
            int code;
            if (sscanf(i + 1, "%2x", &code) != 1) code = TChar('?');
            dest.push_back(TChar(code));
            i += 2;
          }
        else dest.push_back(*i);
      }
  }

  template<typename TChar>
  void decodeQueryString(const std::basic_string<TChar>& src,
                         std::basic_string<TChar>& dest)
  {
    const char * str = src.c_str();
    decodeQueryString(str, str + src.size(), dest);
  }
  

  template<typename TChar>
  void parseQueryString(const std::basic_string<TChar>& queryString,
                        std::map<std::basic_string<TChar>,
                        std::basic_string<TChar> >& queries)
  {
    typedef std::basic_string<TChar> TString;
    typedef typename TString::size_type TSize;
    TSize idxStart = 0;
    TSize idxEQ = queryString.find(TChar('='));
    TSize idxEnd = TString::npos;
    while(TString::npos != idxEQ)
      {
        idxEnd = queryString.find(TChar('&'), idxEQ);

        queries[TString(queryString, idxStart, idxEQ-idxStart)]
          = TString(queryString, idxEQ+1, idxEnd-idxEQ-1);

        idxStart = idxEnd + 1;
        idxEQ = queryString.find(TChar('='), idxEnd);
      }
  }

  template<typename TChar>
  void parseCookieString(const std::basic_string<TChar>& queryString,
                         std::map<std::basic_string<TChar>,
                         std::basic_string<TChar> >& queries)
  {
    typedef std::basic_string<TChar> TString;
    typedef typename TString::size_type TSize;
    TSize idxStart = 0;
    TSize idxEQ = queryString.find(TChar('='));
    TSize idxEnd = TString::npos;
    while(TString::npos != idxEQ)
      {
        idxEnd = queryString.find(TChar(';'), idxEQ);

        for (; isspace(queryString[idxStart]); ++idxStart);

        queries[TString(queryString, idxStart, idxEQ-idxStart)]
          = TString(queryString, idxEQ+1, idxEnd-idxEQ-1);

        idxStart = idxEnd + 1;
        idxEQ = queryString.find(TChar('='), idxEnd);
      }
  }
  

  /** the http-request class
   * Responsibility:
   *    1. parses the query string received from the client
   *    2. keeps http-header variables received from the client
   */
  class Request
  {
    typedef std::map<std::string, std::string> Queries;
    typedef std::map<std::string, std::string> Cookies;
    std::string queryString_;
    std::string cookieString_;
    std::string contentLength_;
    Queries queries_;
    Cookies cookies_;
    
  public:
    Request();

    std::string query(const std::string& name) const;
    std::string cookie(const std::string& name) const;
  };//class request
  
}//namespace cgi
}//namespace yisc

#endif//__yisc_cgi_request_hxx____YAZY__
